Izboljšajte svoje aplikacije Express.js z robustno varnostjo tipov s TypeScriptom. Ta vodnik pokriva definicije obravnav naloge poti, tipizacijo vmesne programske opreme in najboljše prakse.
Integracija TypeScript z Express: Varnost tipov za obravnavo poti
TypeScript je postal temelj sodobnega razvoja JavaScripta, saj ponuja zmožnosti statičnega tipiziranja, ki izboljšujejo kakovost kode, vzdrževanje in razširljivost. V kombinaciji z Express.js, priljubljenim ogrodjem za spletne aplikacije Node.js, lahko TypeScript znatno izboljša robustnost vaših backend API-jev. Ta obsežen vodnik raziskuje, kako uporabiti TypeScript za doseganje varnosti tipov obravnav poti v aplikacijah Express.js, z praktičnimi primeri in najboljšimi praksami za gradnjo robustnih in vzdržljivih API-jev za globalno občinstvo.
Zakaj je varnost tipov pomembna v Express.js
V dinamičnih jezikih, kot je JavaScript, se napake pogosto zaznajo med izvajanjem, kar lahko privede do nepričakovanega vedenja in težko odpravljivih težav. TypeScript to rešuje z uvedbo statičnega tipiziranja, kar vam omogoča, da napake odkrijete med razvojem, preden dosežejo proizvodnjo. V kontekstu Express.js je varnost tipov še posebej ključna za obravnavo poti, kjer delate z objekti zahteve in odgovora, parametri poizvedb in telesi zahtev. Nepravilno obravnavanje teh elementov lahko povzroči zrušitve aplikacije, poškodbe podatkov in varnostne ranljivosti.
- Zgodnje odkrivanje napak: Odkrijte napake, povezane s tipi, med razvojem, kar zmanjšuje verjetnost presenečenj med izvajanjem.
- Izboljšano vzdrževanje kode: Anotacije tipov olajšajo razumevanje in refaktoriranje kode.
- Izboljšano samodejno dokončanje kode in orodja: IDE lahko zagotovijo boljše predloge in preverjanje napak s podatki o tipih.
- Zmanjšanje napak: Varnost tipov pomaga preprečiti pogoste programerske napake, kot je posredovanje napačnih podatkovnih tipov funkcijam.
Nastavitev projekta TypeScript Express.js
Preden se poglobimo v varnost tipov obravnav poti, nastavimo osnovni projekt TypeScript Express.js. To bo služilo kot osnova za naše primere.
Predpogoji
- Nameščen Node.js in npm (Node Package Manager). Prenesete jih lahko z uradne spletne strani Node.js. Zagotovite, da imate nedavno različico za optimalno združljivost.
- Urejevalnik kode, kot je Visual Studio Code, ki ponuja odlično podporo za TypeScript.
Inicializacija projekta
- Ustvarite nov imenik projekta:
mkdir typescript-express-app && cd typescript-express-app - Inicializirajte nov projekt npm:
npm init -y - Namestite TypeScript in Express.js:
npm install typescript express - Namestite datoteke deklaracij TypeScript za Express.js (pomembno za varnost tipov):
npm install @types/express @types/node - Inicializirajte TypeScript:
npx tsc --init(To ustvari datotekotsconfig.json, ki konfigurira prevajalnik TypeScript.)
Konfiguracija TypeScript
Odprite datoteko tsconfig.json in jo ustrezno konfigurirajte. Tukaj je vzorčna konfiguracija:
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
}
}
Ključne konfiguracije, ki si jih je treba zapomniti:
target: Določa ciljno različico ECMAScripta.es6je dobra izhodiščna točka.module: Določa generiranje modulske kode.commonjsje pogosta izbira za Node.js.outDir: Določa izhodni imenik za prevedene datoteke JavaScript.rootDir: Določa korenski imenik vaših izvornih datotek TypeScript.strict: Omogoči vse možnosti strogega preverjanja tipov za izboljšano varnost tipov. To je zelo priporočljivo.esModuleInterop: Omogoča interoperabilnost med moduli CommonJS in ES.
Ustvarjanje vstopne točke
Ustvarite imenik src in dodajte datoteko index.ts:
mkdir src
touch src/index.ts
Datoteko src/index.ts napolnite z osnovno nastavitvijo strežnika Express.js:
import express, { Request, Response } from 'express';
const app = express();
const port = 3000;
app.get('/', (req: Request, res: Response) => {
res.send('Hello, TypeScript Express!');
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
Dodajanje skripta za gradnjo
Dodajte skript za gradnjo v svojo datoteko package.json za prevajanje kode TypeScript:
"scripts": {
"build": "tsc",
"start": "node dist/index.js",
"dev": "npm run build && npm run start"
}
Zdaj lahko zaženete npm run dev za prevajanje in zagon strežnika.
Varnost tipov obravnav poti: Definiranje tipov zahtev in odgovorov
Jedro varnosti tipov obravnav poti je pravilno definiranje tipov za objekte Request in Response. Express.js ponuja generične tipe za te objekte, ki vam omogočajo, da določite tipe parametrov poizvedb, telesa zahteve in parametrov poti.
Osnovni tipi obravnav poti
Začnimo s preprostim obravnavo poti, ki pričakuje ime kot parameter poizvedbe:
import express, { Request, Response } from 'express';
const app = express();
const port = 3000;
interface NameQuery {
name: string;
}
app.get('/hello', (req: Request<any, any, any, NameQuery>, res: Response) => {
const name = req.query.name;
if (!name) {
return res.status(400).send('Parameter name je obvezen.');
}
res.send(`Hello, ${name}!`);
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
V tem primeru:
Request<any, any, any, NameQuery>definira tip za objekt zahteve.- Prvi
anypredstavlja parametre poti (npr./users/:id). - Drugi
anypredstavlja tip telesa odgovora. - Tretji
anypredstavlja tip telesa zahteve. NameQueryje vmesnik, ki definira strukturo parametrov poizvedb.
Z definiranjem vmesnika NameQuery lahko TypeScript zdaj preveri, ali lastnost req.query.name obstaja in je tipa string. Če poskusite dostopiti do neobstoječe lastnosti ali dodeliti vrednost napačnega tipa, bo TypeScript označil napako.
Obravnavanje teles zahtev
Za poti, ki sprejemajo telesa zahtev (npr. POST, PUT, PATCH), lahko definirate vmesnik za telo zahteve in ga uporabite v tipu Request:
import express, { Request, Response } from 'express';
import bodyParser from 'body-parser';
const app = express();
const port = 3000;
app.use(bodyParser.json()); // Pomembno za razčlenjevanje teles JSON zahtev
interface CreateUserRequest {
firstName: string;
lastName: string;
email: string;
}
app.post('/users', (req: Request<any, any, CreateUserRequest>, res: Response) => {
const { firstName, lastName, email } = req.body;
// Validacija telesa zahteve
if (!firstName || !lastName || !email) {
return res.status(400).send('Manjkajoča zahtevana polja.');
}
// Obdelava ustvarjanja uporabnika (npr. shranjevanje v bazo podatkov)
console.log(`Ustvarjanje uporabnika: ${firstName} ${lastName} (${email})`);
res.status(201).send('Uporabnik uspešno ustvarjen.');
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
V tem primeru:
CreateUserRequestdefinira strukturo pričakovanega telesa zahteve.app.use(bodyParser.json())je ključen za razčlenjevanje teles JSON zahtev. Brez njega boreq.bodynedefiniran.- Tip
Requestje zdajRequest<any, any, CreateUserRequest>, kar kaže, da mora objektreq.bodyustrezati vmesnikuCreateUserRequest.
TypeScript bo zdaj zagotovil, da objekt req.body vsebuje pričakovane lastnosti (firstName, lastName in email) in da so njihovi tipi pravilni. To znatno zmanjša tveganje napak med izvajanjem, ki jih povzročijo nepravilni podatki v telesu zahteve.
Obravnavanje parametrov poti
Za poti s parametri (npr. /users/:id) lahko definirate vmesnik za parametre poti in ga uporabite v tipu Request:
import express, { Request, Response } from 'express';
const app = express();
const port = 3000;
interface UserParams {
id: string;
}
interface User {
id: string;
firstName: string;
lastName: string;
email: string;
}
const users: User[] = [
{ id: '1', firstName: 'John', lastName: 'Doe', email: 'john.doe@example.com' },
{ id: '2', firstName: 'Jane', lastName: 'Smith', email: 'jane.smith@example.com' },
];
app.get('/users/:id', (req: Request<UserParams>, res: Response) => {
const userId = req.params.id;
const user = users.find(u => u.id === userId);
if (!user) {
return res.status(404).send('Uporabnik ni najden.');
}
res.json(user);
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
V tem primeru:
UserParamsdefinira strukturo parametrov poti in določa, da mora biti parameteridniz.- Tip
Requestje zdajRequest<UserParams>, kar kaže, da mora objektreq.paramsustrezati vmesnikuUserParams.
TypeScript bo zdaj zagotovil, da lastnost req.params.id obstaja in je tipa string. To pomaga preprečiti napake, povzročene z dostopom do neobstoječih parametrov poti ali z njihovo uporabo z nepravilnimi tipi.
Določanje tipov odgovorov
Čeprav je osredotočenost na varnost tipov zahtevkov ključna, definiranje tipov odgovorov tudi izboljšuje jasnost kode in pomaga preprečevati nedoslednosti. Lahko definirate tip podatkov, ki jih pošiljate nazaj v odgovoru.
import express, { Request, Response } from 'express';
const app = express();
const port = 3000;
interface User {
id: string;
firstName: string;
lastName: string;
email: string;
}
const users: User[] = [
{ id: '1', firstName: 'John', lastName: 'Doe', email: 'john.doe@example.com' },
{ id: '2', firstName: 'Jane', lastName: 'Smith', email: 'jane.smith@example.com' },
];
app.get('/users', (req: Request, res: Response<User[]>) => {
res.json(users);
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
Tukaj Response<User[]> določa, da mora biti telo odgovora niz objektov User. To pomaga zagotoviti, da dosledno pošiljate pravilno strukturo podatkov v odgovorih API-ja. Če poskusite poslati podatke, ki ne ustrezajo tipu User[], bo TypeScript izdal opozorilo.
Varnost tipov vmesne programske opreme
Vmesne funkcije so bistvene za obravnavanje prečnih pomislekov v aplikacijah Express.js. Zagotavljanje varnosti tipov v vmesni programski opremi je prav tako pomembno kot pri obravnavavah poti.
Tipiziranje vmesnih funkcij
Osnovna struktura vmesne funkcije v TypeScriptu je podobna kot pri obravnavavah poti:
import express, { Request, Response, NextFunction } from 'express';
function authenticationMiddleware(req: Request, res: Response, next: NextFunction) {
// Logika avtentikacije
const isAuthenticated = true; // Zamenjajte z dejansko preverjanje avtentikacije
if (isAuthenticated) {
next(); // Nadaljujte z naslednjo vmesno programsko opremo ali obravnavo poti
} else {
res.status(401).send('Neavtorizirano');
}
}
const app = express();
const port = 3000;
app.use(authenticationMiddleware);
app.get('/', (req: Request, res: Response) => {
res.send('Hello, authenticated user!');
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
V tem primeru:
NextFunctionje tip, ki ga ponuja Express.js in predstavlja naslednjo vmesno funkcijo v verigi.- Vmesna funkcija sprejema iste objekte
RequestinResponsekot obravnavanje poti.
Povečanje objekta Request
Včasih boste morda želeli dodati lastne lastnosti objektu Request v vaši vmesni programski opremi. Na primer, vmesna programska oprema za avtentikacijo bi lahko dodala lastnost user k objektu zahteve. Če želite to storiti na varen način s tipi, morate povečati vmesnik Request.
import express, { Request, Response, NextFunction } from 'express';
interface User {
id: string;
username: string;
email: string;
}
// Povečaj vmesnik Request
declare global {
namespace Express {
interface Request {
user?: User;
}
}
}
function authenticationMiddleware(req: Request, res: Response, next: NextFunction) {
// Logika avtentikacije (zamenjajte z dejanskim preverjanjem avtentikacije)
const user: User = { id: '123', username: 'johndoe', email: 'john.doe@example.com' };
req.user = user; // Dodaj uporabnika k objektu zahteve
next(); // Nadaljujte z naslednjo vmesno programsko opremo ali obravnavo poti
}
const app = express();
const port = 3000;
app.use(authenticationMiddleware);
app.get('/', (req: Request, res: Response) => {
const username = req.user?.username || 'Gost';
res.send(`Hello, ${username}!`);
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
V tem primeru:
- Uporabimo globalno deklaracijo za povečanje vmesnika
Express.Request. - Dodamo izbirno lastnost
usertipaUservmesnikuRequest. - Zdaj lahko dostopate do lastnosti
req.userv svojih obravnavah poti, ne da bi TypeScript javil napako. `?` v `req.user?.username` je ključen za obravnavanje primerov, ko uporabnik ni avtenticiran, kar preprečuje morebitne napake.
Najboljše prakse za integracijo TypeScript Express
Če želite kar najbolje izkoristiti prednosti TypeScripta v svojih aplikacijah Express.js, upoštevajte te najboljše prakse:
- Omogočite strogi način: Uporabite možnost
"strict": truev svoji datotekitsconfig.json, da omogočite vse možnosti strogega preverjanja tipov. To pomaga zgodaj odkriti potencialne napake in zagotavlja višjo raven varnosti tipov. - Uporabite vmesnike in tipe aliasov: Definirajte vmesnike in tipe aliasov za predstavitev strukture vaših podatkov. To naredi vašo kodo bolj berljivo in vzdržljivo.
- Uporabite generične tipe: Izkoristite generične tipe za ustvarjanje ponovno uporabnih in varnih komponent s tipi.
- Napišite enotske teste: Napišite enotske teste za preverjanje pravilnosti vaše kode in zagotovite, da so vaše anotacije tipov točne. Testiranje je ključnega pomena za ohranjanje kakovosti kode.
- Uporabite linter in oblikovalnik: Uporabite linter (kot je ESLint) in oblikovalnik (kot je Prettier) za uveljavljanje doslednih slogov kodiranja in odkrivanje potencialnih napak.
- Izogibajte se tipu
any: Zmanjšajte uporabo tipaany, saj obide preverjanje tipov in izniči namen uporabe TypeScripta. Uporabljajte ga le, ko je nujno potrebno, in po možnosti uporabite bolj specifične tipe ali generike. - Logično strukturirajte svoj projekt: Organizirajte svoj projekt v module ali mape glede na funkcionalnost. To bo izboljšalo vzdržljivost in razširljivost vaše aplikacije.
- Uporabite vnašanje odvisnosti: Razmislite o uporabi posode za vnašanje odvisnosti za upravljanje odvisnosti vaše aplikacije. To lahko naredi vašo kodo bolj testabilno in vzdržljivo. Knjižnice, kot je InversifyJS, so priljubljene izbire.
Napredni koncepti TypeScript za Express.js
Uporaba dekoraterjev
Dekoraterji ponujajo jedrnat in izrazit način dodajanja metapodatkov razredom in funkcijam. Dekoraterje lahko uporabite za poenostavitev registracije poti v Express.js.
Najprej morate omogočiti eksperimentalne dekoraterje v vaši datoteki tsconfig.json z dodajanjem "experimentalDecorators": true v compilerOptions.
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"experimentalDecorators": true
}
}
Nato lahko ustvarite dekorater po meri za registracijo poti:
import express, { Router, Request, Response } from 'express';
function route(method: string, path: string) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
if (!target.__router__) {
target.__router__ = Router();
}
target.__router__[method](path, descriptor.value);
};
}
class UserController {
@route('get', '/users')
getUsers(req: Request, res: Response) {
res.send('Seznam uporabnikov');
}
@route('post', '/users')
createUser(req: Request, res: Response) {
res.status(201).send('Uporabnik ustvarjen');
}
public getRouter() {
return this.__router__;
}
}
const userController = new UserController();
const app = express();
const port = 3000;
app.use('/', userController.getRouter());
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
V tem primeru:
- Dekorater
routesprejema metode HTTP in pot kot argumente. - Okrašeno metodo registrira kot obravnavo poti na usmerjevalniku, povezanem z razredom.
- To poenostavi registracijo poti in naredi vašo kodo bolj berljivo.
Uporaba varnostnih tipov po meri
Varnostni tipi so funkcije, ki zožijo tip spremenljivke v določenem obsegu. Varnostne tipe po meri lahko uporabite za validacijo teles zahtev ali parametrov poizvedb.
interface Product {
id: string;
name: string;
price: number;
}
function isProduct(obj: any): obj is Product {
return typeof obj === 'object' &&
obj !== null &&
typeof obj.id === 'string' &&
typeof obj.name === 'string' &&
typeof obj.price === 'number';
}
import express, { Request, Response } from 'express';
import bodyParser from 'body-parser';
const app = express();
const port = 3000;
app.use(bodyParser.json());
app.post('/products', (req: Request, res: Response) => {
if (!isProduct(req.body)) {
return res.status(400).send('Neveljavni podatki o izdelku');
}
const product: Product = req.body;
console.log(`Ustvarjanje izdelka: ${product.name}`);
res.status(201).send('Izdelek ustvarjen');
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
V tem primeru:
- Funkcija
isProductje varnostni tip po meri, ki preveri, ali objekt ustreza vmesnikuProduct. - Znotraj obravnavo poti
/productsfunkcijaisProductse uporablja za validacijo telesa zahteve. - Če je telo zahteve veljaven izdelek, TypeScript ve, da je
req.bodytipaProductznotraj blokaif.
Obravnavanje globalnih vidikov pri načrtovanju API-jev
Pri načrtovanju API-jev za globalno občinstvo je treba upoštevati več dejavnikov, da zagotovimo dostopnost, uporabnost in kulturno občutljivost.
- Lokalizacija in internacionalizacija (i18n in L10n):
- Pogajanje o vsebini: Podprite več jezikov in regij s pogajanjem o vsebini, ki temelji na glavi
Accept-Language. - Oblikovanje datuma in časa: Uporabite format ISO 8601 za predstavitev datuma in časa, da se izognete dvoumnosti med različnimi regijami.
- Oblikovanje številk: Obravnavajte oblikovanje številk v skladu z lokalno nastavitvijo uporabnika (npr. decimalni in tisočični ločilniki).
- Obravnavanje valute: Podprite več valut in po potrebi zagotovite informacije o menjalnih tečajih.
- Smer besedila: Prilagodite jezike od desne proti levi (RTL), kot sta arabščina in hebrejščina.
- Pogajanje o vsebini: Podprite več jezikov in regij s pogajanjem o vsebini, ki temelji na glavi
- Časovni pasovi:
- Datume in čase na strani strežnika shranjujte v UTC (koordiniranem univerzalnem času).
- Uporabnikom omogočite, da določijo svoj želeni časovni pas, in ustrezno pretvorite datume in čase na strani odjemalca.
- Uporabite knjižnice, kot je
moment-timezone, za obravnavanje pretvorb časovnih pasov.
- Kodiranje znakov:
- Uporabite kodiranje UTF-8 za vse besedilne podatke, da podprete širok nabor znakov iz različnih jezikov.
- Zagotovite, da so vaša baza podatkov in drugi sistemi za shranjevanje podatkov konfigurirani za uporabo UTF-8.
- Dostopnost:
- Upoštevajte smernice za dostopnost (npr. WCAG), da bo vaš API dostopen uporabnikom z okvarami.
- Zagotovite jasna in opisna sporočila o napakah, ki so lahko razumljiva.
- Uporabite semantične HTML elemente in atribute ARIA v dokumentaciji API-ja.
- Kulturna občutljivost:
- Izogibajte se uporabi kulturnih referenc, idiomov ali humorja, ki jih vsi uporabniki morda ne bodo razumeli.
- Bodite pozorni na kulturne razlike v komunikacijskih slogih in preferencah.
- Razmislite o potencialnem vplivu vašega API-ja na različne kulturne skupine in se izogibajte ponavljajočim se stereotipom ali pristranskostim.
- Zasebnost in varnost podatkov:
- Upoštevajte predpise o zasebnosti podatkov, kot sta GDPR (Splošna uredba o varstvu podatkov) in CCPA (Zakon o varstvu potrošnikov v Kaliforniji).
- Implementirajte močne mehanizme avtentikacije in avtorizacije za zaščito uporabniških podatkov.
- Občutljive podatke šifrirajte tako med prenosom kot pri shranjevanju.
- Uporabnikom omogočite nadzor nad njihovimi podatki in jim dovolite dostop, spreminjanje in brisanje njihovih podatkov.
- Dokumentacija API-ja:
- Zagotovite obsežno in dobro organizirano dokumentacijo API-ja, ki jo je enostavno razumeti in po njej krmariti.
- Uporabite orodja, kot je Swagger/OpenAPI, za generiranje interaktivne dokumentacije API-ja.
- Vključite primere kod v več programskih jezikih, da boste ustregli raznolikemu občinstvu.
- Prevedite svojo dokumentacijo API-ja v več jezikov, da dosežete širše občinstvo.
- Obravnavanje napak:
- Zagotovite specifična in informativna sporočila o napakah. Izogibajte se splošnim sporočilom o napakah, kot je "Nekaj je šlo narobe."
- Uporabite standardne HTTP statusne kode, da označite vrsto napake (npr. 400 za napačno zahtevo, 401 za neavtorizirano, 500 za notranjo napako strežnika).
- Vključite kode napak ali identifikatorje, ki jih je mogoče uporabiti za sledenje in odpravljanje težav.
- Prijavite napake na strani strežnika za odpravljanje napak in spremljanje.
- Omejevanje stopnje: Implementirajte omejevanje stopnje, da zaščitite svoj API pred zlorabo in zagotovite pošteno uporabo.
- Različice: Uporabite različice API-ja, da omogočite združljive spremembe in se izognete pokvaritvi obstoječih odjemalcev.
Zaključek
Integracija TypeScript z Express bistveno izboljša zanesljivost in vzdržljivost vaših backend API-jev. Z izkoriščanjem varnosti tipov pri obravnavanju poti in vmesne programske opreme lahko zgodaj odkrijete napake v razvojnem procesu in ustvarite bolj robustne in razširljive aplikacije za globalno občinstvo. Z definiranjem tipov zahtev in odgovorov zagotovite, da vaš API sledi dosledni strukturi podatkov, kar zmanjšuje verjetnost napak med izvajanjem. Ne pozabite upoštevati najboljših praks, kot je omogočanje strogega načina, uporaba vmesnikov in tipov aliasov ter pisanje enotskih testov, da kar najbolje izkoristite prednosti TypeScripta. Vedno upoštevajte globalne dejavnike, kot so lokalizacija, časovni pasovi in kulturna občutljivost, da zagotovite, da so vaši API-ji dostopni in uporabni po vsem svetu.